
#include "linux/mm.h"
#include "linux/string.h"
#include "linux/bug.h"
#include "linux/config.h"
#include "linux/printk.h"
#include "linux/page.h"
#include "linux/error.h"
#include "linux/sched.h"
#include "linux/pagemap.h"

#include "linux/errno.h"
#include "asm/pgtable.h"

int ioremap_pte_range(pmd_t *pmd, unsigned long vaddr, unsigned long vend, phys_addr_t phys_addr, pgprot_t prot)
{
    pte_t *pte;
    pte_t entry;
    
    pte = pte_alloc(pmd, vaddr);
    if (!pte)
        return -ENOMEM;

    do 
    {
        entry.pte = phys_addr;
        set_pte(pte, entry);

        vaddr = (vaddr + PAGE_SIZE) & PAGE_MASK;
        phys_addr = (phys_addr + PAGE_SIZE) & PAGE_MASK;
        pte++;
    } while (vaddr < vend);

    return 0;
}

int ioremap_pmd_range(pgd_t *pgd, unsigned long vaddr, unsigned long vend, phys_addr_t phys_addr, pgprot_t prot)
{
    int err;
    pmd_t *pmd;
    
    if (pgd_none(pgd))
        return 0;
    
    if (pgd_bad(*pgd))
    {
        pgd_ERROR(*pgd);
        pgd_clear(pgd);
        return 0;
    }

    pmd = pmd_alloc(pgd, vaddr);
    if (!pmd)
        return -ENOMEM;

    do 
    {
        err = ioremap_pte_range(pmd, vaddr, vend, phys_addr, prot);
        if (err)
        {

        }
        phys_addr = (phys_addr  + PMD_SIZE) & PMD_MASK;
        vaddr = (vaddr + PMD_SIZE) & PMD_MASK;
        pmd++;
    } while (vaddr < vend);

    return 0;
}

int ioremap_page_range(unsigned long vaddr, unsigned long vend, phys_addr_t phys_addr, pgprot_t prot)
{
    pgd_t *pgd;
    int err = 0;

    pgd = pgd_offset(&init_mm, vaddr);
    do 
    {
        err = ioremap_pmd_range(pgd, vaddr, vend, phys_addr, prot);
        if (!err)
        {

        }

        phys_addr = (phys_addr + PGDIR_SIZE) & PGDIR_MASK;
        vaddr = (vaddr + PGDIR_SIZE) & PGDIR_MASK;
        pgd++;
    } while (vaddr && (vaddr < vend));
    
    return err;
}